import { ref, computed, watch, Ref, onMounted, onUnmounted } from 'vue'
import { ContainerProvider, MatchedLine, ReferenceLineMap, ResizingHandle } from './types'
import {
  getElSize,
  getId,
  filterHandles,
  addEvent,
  removeEvent,
  getReferenceLineMap,
  getAngle,
  getLength,
  degToRadian,
  cos,
  sin,
} from './utils'

export function useState<T>(initialState: T): [Ref<T>, (value: T) => T] {
  const state = ref(initialState) as Ref<T>
  const setState = (value: T): T => {
    state.value = value
    return value
  }
  return [state, setState]
}

// 初始化变量和设置变量的方法
export function initState(props: any, emit: any) {
  const [width, setWidth] = useState<number>(props.initW)
  const [height, setHeight] = useState<number>(props.initH)
  const [left, setLeft] = useState<number>(props.x)
  const [top, setTop] = useState<number>(props.y)
  const [angle, setAngle] = useState<number>(props.angle)
  const [enable, setEnable] = useState<boolean>(props.active)
  const [dragging, setDragging] = useState<boolean>(false)
  const [resizing, setResizing] = useState<boolean>(false)
  const [rotating, setRotating] = useState<boolean>(false)
  const [resizingHandle, setResizingHandle] = useState<ResizingHandle>('')
  const [resizingMaxWidth, setResizingMaxWidth] = useState<number>(Infinity)
  const [resizingMaxHeight, setResizingMaxHeight] = useState<number>(Infinity)
  const [resizingMinWidth, setResizingMinWidth] = useState<number>(props.minW)
  const [resizingMinHeight, setResizingMinHeight] = useState<number>(props.minH)
  // 缩放比例
  const aspectRatio = computed(() => height.value / width.value)

  // 监听数据的变化
  watch(
    width,
    newVal => {
      emit('update:w', newVal)
    },
    { immediate: true }
  )
  watch(
    height,
    newVal => {
      emit('update:h', newVal)
    },
    { immediate: true }
  )
  watch(top, newVal => {
    emit('update:y', newVal)
  })
  watch(left, newVal => {
    emit('update:x', newVal)
  })
  watch(angle, newVal => {
    emit('update:angle', newVal)
  })
  watch(enable, (newVal, oldVal) => {
    emit('update:active', newVal)
    if (!oldVal && newVal) {
      emit('activated')
    } else if (oldVal && !newVal) {
      emit('deactivated')
    }
  })
  watch(
    () => props.active,
    (newVal: boolean) => {
      setEnable(newVal)
    }
  )
  return {
    id: getId(),
    width,
    height,
    top,
    left,
    angle,
    enable,
    dragging,
    resizing,
    rotating,
    resizingHandle,
    resizingMaxWidth,
    resizingMaxHeight,
    resizingMinWidth,
    resizingMinHeight,
    aspectRatio,
    setWidth: (val: number) => setWidth(Math.round(val)),
    setHeight: (val: number) => setHeight(Math.round(val)),
    setTop: (val: number) => setTop(Number(val.toFixed(3))),
    setLeft: (val: number) => setLeft(Number(val.toFixed(3))),
    setAngle,
    setEnable,
    setDragging,
    setResizing,
    setRotating,
    setResizingHandle,
    setResizingMaxWidth,
    setResizingMaxHeight,
    setResizingMinWidth,
    setResizingMinHeight,
  }
}
// 父元素
export function initParent(containerRef: Ref<HTMLElement | undefined>) {
  const parentWidth = ref(0)
  const parentHeight = ref(0)
  const parentLeft = ref(0)
  const parentTop = ref(0)
  onMounted(() => {
    if (containerRef.value && containerRef.value.parentElement) {
      const { width, height, left, top } = getElSize(containerRef.value.parentElement)
      parentWidth.value = width
      parentHeight.value = height
      parentLeft.value = left
      parentTop.value = top
    }
  })
  return {
    parentWidth,
    parentHeight,
    parentLeft,
    parentTop,
  }
}

// 处理边界取值
export function initLimitSizeAndMethods(
  props: any,
  containerProps: ReturnType<typeof initState>,
  parentSize: ReturnType<typeof initParent>
) {
  const {
    width,
    height,
    left,
    top,
    resizingMaxWidth,
    resizingMaxHeight,
    resizingMinWidth,
    resizingMinHeight,
  } = containerProps
  const { setWidth, setHeight, setTop, setLeft } = containerProps
  const { parentWidth, parentHeight } = parentSize

  const limitProps = {
    minWidth: computed(() => {
      return resizingMinWidth.value // props.minW
    }),
    minHeight: computed(() => {
      return resizingMinHeight.value // props.minH
    }),
    maxWidth: computed(() => {
      let max = Infinity
      if (props.parent) {
        max = Math.min(parentWidth.value, resizingMaxWidth.value) // parent, Infinity
      }
      return max
    }),
    maxHeight: computed(() => {
      let max = Infinity
      if (props.parent) {
        max = Math.min(parentHeight.value, resizingMaxHeight.value)
      }
      return max
    }),
    minLeft: computed(() => {
      return props.parent ? 0 : -Infinity
    }),
    minTop: computed(() => {
      return props.parent ? 0 : -Infinity
    }),
    maxLeft: computed(() => {
      return props.parent ? parentWidth.value - width.value : Infinity
    }),
    maxTop: computed(() => {
      return props.parent ? parentHeight.value - height.value : Infinity
    }),
  }
  // 设置宽高时的一些边界取值
  const limitMethods = {
    setWidth(val: number) {
      // width不能改变时
      if (props.disabledW) {
        return width.value
      }
      // 设置的宽不能大于maxWidth，最小不能小于minWidth
      return setWidth(Math.min(limitProps.maxWidth.value, Math.max(limitProps.minWidth.value, val)))
    },
    setHeight(val: number) {
      if (props.disabledH) {
        return height.value
      }
      return setHeight(
        Math.min(limitProps.maxHeight.value, Math.max(limitProps.minHeight.value, val))
      )
    },
    setTop(val: number) {
      if (props.disabledY) {
        return top.value
      }
      return setTop(Math.min(limitProps.maxTop.value, Math.max(limitProps.minTop.value, val)))
    },
    setLeft(val: number) {
      if (props.disabledX) {
        return left.value
      }
      return setLeft(Math.min(limitProps.maxLeft.value, Math.max(limitProps.minLeft.value, val)))
    },
    setAngle(val: number) {
      return val
    },
  }

  return {
    ...limitProps,
    ...limitMethods,
  }
}

type HandleEvent = MouseEvent | TouchEvent

const DOWN_HANDLES: (keyof HTMLElementEventMap)[] = ['mousedown', 'touchstart']
const UP_HANDLES: (keyof HTMLElementEventMap)[] = ['mouseup', 'touchend']
const MOVE_HANDLES: (keyof HTMLElementEventMap)[] = ['mousemove', 'touchmove']

function getPosition(e: HandleEvent) {
  if ('touches' in e) {
    return [e.touches[0].pageX, e.touches[0].pageY]
  } else {
    return [e.pageX, e.pageY]
  }
}

/**
 * 初始化draggableContainer
 * 选中事件，drag事件
 */
export function initDraggableContainer(
  containerRef: Ref<HTMLElement | undefined>,
  containerProps: ReturnType<typeof initState>,
  limitProps: ReturnType<typeof initLimitSizeAndMethods>,
  draggable: Ref<boolean>,
  emit: any,
  containerProvider: ContainerProvider | null,
  parentSize: ReturnType<typeof initParent>
): { containerRef: Ref<HTMLElement | undefined> } {
  // 获取container的信息
  const { left: x, top: y, width: w, height: h, angle, dragging, id } = containerProps
  const { setDragging, setEnable, setResizing, setResizingHandle } = containerProps
  // 边界设置方法
  const { setTop, setLeft } = limitProps
  let lastX = 0 // left 初始
  let lastY = 0 // top 初始
  let lastPageX = 0 // 鼠标初始pageX
  let lastPageY = 0 // 鼠标初始pageY

  let referenceLineMap: ReferenceLineMap | null = null

  const documentElement = document.documentElement

  const _unselect = (e: HandleEvent) => {
    const target = e.target
    if (!containerRef.value?.contains(<Node>target)) {
      setEnable(false)
      setDragging(false)
      setResizing(false)
      setResizingHandle('')
    }
  }
  // drag
  const handleDrag = (e: MouseEvent) => {
    e.preventDefault()
    if (!(dragging.value && containerRef.value)) return
    const [pageX, pageY] = getPosition(e)
    const deltaX = pageX - lastPageX
    const deltaY = pageY - lastPageY
    let newLeft = lastX + deltaX
    let newTop = lastY + deltaY
    if (referenceLineMap !== null) {
      const widgetSelfLine = {
        col: [newLeft, newLeft + w.value / 2, newLeft + w.value],
        row: [newTop, newTop + h.value / 2, newTop + h.value],
      }
      const matchedLine: unknown = {
        row: widgetSelfLine.row
          .map((i, index) => {
            let match = null
            Object.values(referenceLineMap!.row).forEach(referItem => {
              if (i >= referItem.min && i <= referItem.max) {
                match = referItem.value
              }
            })
            if (match !== null) {
              if (index === 0) {
                newTop = match
              } else if (index === 1) {
                newTop = Math.floor(match - h.value / 2)
              } else if (index === 2) {
                newTop = Math.floor(match - h.value)
              }
            }
            return match
          })
          .filter(i => i !== null),
        col: widgetSelfLine.col
          .map((i, index) => {
            let match = null
            Object.values(referenceLineMap!.col).forEach(referItem => {
              if (i >= referItem.min && i <= referItem.max) {
                match = referItem.value
              }
            })
            if (match !== null) {
              if (index === 0) {
                newLeft = match
              } else if (index === 1) {
                newLeft = Math.floor(match - w.value / 2)
              } else if (index === 2) {
                newLeft = Math.floor(match - w.value)
              }
            }
            return match
          })
          .filter(i => i !== null),
      }
      containerProvider!.setMatchedLine(matchedLine as MatchedLine)
    }
    emit('dragging', { x: setLeft(newLeft), y: setTop(newTop) })
  }
  // drag-end
  const handleUp = (e: MouseEvent) => {
    setDragging(false)
    // document.documentElement.removeEventListener('mouseup', handleUp)
    // document.documentElement.removeEventListener('mousemove', handleDrag)
    removeEvent(documentElement, UP_HANDLES, handleUp)
    removeEvent(documentElement, MOVE_HANDLES, handleDrag)
    referenceLineMap = null
    if (containerProvider) {
      containerProvider.updatePosition(id, {
        x: x.value,
        y: y.value,
        w: w.value,
        h: h.value,
        angle: angle.value,
      })
      containerProvider.setMatchedLine(null)
    }
  }

  // 鼠标按下事件
  const handleDown = (e: HandleEvent) => {
    if (!draggable.value) return
    setDragging(true)
    setEnable(true)
    lastX = x.value
    lastY = y.value
    lastPageX = getPosition(e)[0]
    lastPageY = getPosition(e)[1]
    // document.documentElement.addEventListener('mousemove', handleDrag)
    // document.documentElement.addEventListener('mouseup', handleUp)
    addEvent(documentElement, MOVE_HANDLES, handleDrag)
    addEvent(documentElement, UP_HANDLES, handleUp)
    if (containerProvider && !containerProvider.disabled.value) {
      referenceLineMap = getReferenceLineMap(containerProvider, parentSize, id)
    }
  }
  watch(dragging, (cur, pre) => {
    if (!pre && cur) {
      emit('drag-start', { x: x.value, y: y.value })
      setDragging(true)
    } else {
      emit('drag-end', { x: x.value, y: y.value })
      setDragging(false)
    }
  })

  onMounted(() => {
    const el = containerRef.value
    if (!el) return
    el.style.left = x + 'px'
    el.style.top = y + 'px'
    // 绑定事件
    // document.documentElement.addEventListener('mousedown', _unselect)
    // el.addEventListener('mousedown', handleDown)
    addEvent(documentElement, DOWN_HANDLES, _unselect)
    addEvent(el, DOWN_HANDLES, handleDown)
  })

  onUnmounted(() => {
    // 解绑事件
    if (!containerRef.value) return
    // document.documentElement.removeEventListener('mousedown', _unselect)
    // document.documentElement.removeEventListener('mouseup', handleUp)
    // document.documentElement.removeEventListener('mousemove', handleDrag)
    removeEvent(documentElement, DOWN_HANDLES, _unselect)
    removeEvent(documentElement, UP_HANDLES, handleUp)
    removeEvent(documentElement, MOVE_HANDLES, handleDrag)
  })
  return { containerRef }
}

// 初始化handles
export function initResizeHandle(
  containerRef: Ref<HTMLElement | undefined>,
  containerProps: ReturnType<typeof initState>,
  limitProps: ReturnType<typeof initLimitSizeAndMethods>,
  parentSize: ReturnType<typeof initParent>,
  props: any,
  emit: any
) {
  const { setWidth, setHeight, setLeft, setTop } = limitProps
  const { width, height, left, top, angle, aspectRatio } = containerProps
  const {
    setResizing,
    setResizingHandle,
    setResizingMaxWidth,
    setResizingMaxHeight,
    setResizingMinWidth,
    setResizingMinHeight,
  } = containerProps
  const { parentWidth, parentHeight } = parentSize
  let lastW = 0
  let lastH = 0
  let lastX = 0 // left
  let lastY = 0 // top
  let lastAngle = 0
  let lastPageX = 0
  let lastPageY = 0
  let tmpAspectRatio = 1
  let idx0 = '' // t  b
  let idx1 = '' // l  r
  let lastCenter = {
    x: 0,
    y: 0,
  }

  const documentElement = document.documentElement

  const resizeHandleDrag = (e: HandleEvent) => {
    e.preventDefault()
    e.stopImmediatePropagation()
    const [pageX, pageY] = getPosition(e)
    const deltaX = pageX - lastPageX
    const deltaY = pageY - lastPageY
    const alpha = Math.atan2(deltaY, deltaX) // 弧度，一个 -pi 到 pi 之间的数值，表示点 (x, y) 对应的偏移角度
    const deltaL = getLength(deltaX, deltaY) // 两点之间的线段长度

    const deltaRadian = alpha - degToRadian(lastAngle) // 弧度差
    let deltaW = deltaL * Math.cos(deltaRadian) // w差
    let deltaH = deltaL * Math.sin(deltaRadian) // h差
    const lastAngleCos = cos(lastAngle)
    const lastAngleSin = sin(lastAngle)
    let currentW = lastW
    let currentH = lastH
    const center = { ...lastCenter }

    switch (idx0) {
      case 't':
        if (idx1 === 'l') {
          deltaW = -deltaW
          deltaH = -deltaH
          currentH = lastH + deltaH
          currentW = lastW + deltaW
          if (props.lockAspectRatio || (!props.lockAspectRatio && props.vertexRatio)) {
            if (currentH / currentW < tmpAspectRatio) {
              currentW = currentH / tmpAspectRatio
              deltaW = deltaH / tmpAspectRatio
            } else {
              currentH = currentW * tmpAspectRatio
              deltaH = deltaW * tmpAspectRatio
            }
          }
          center.x -= (deltaW / 2) * lastAngleCos - (deltaH / 2) * lastAngleSin
          center.y -= (deltaW / 2) * lastAngleSin + (deltaH / 2) * lastAngleCos
        } else if (idx1 === 'm') {
          deltaH = -deltaH
          currentH = lastH + deltaH
          if (props.lockAspectRatio) {
            if (currentH / currentW < tmpAspectRatio) {
              currentW = currentH / tmpAspectRatio
              deltaW = deltaH / tmpAspectRatio
            } else {
              currentH = currentW * tmpAspectRatio
              deltaH = deltaW * tmpAspectRatio
            }
            // 左下角固定
            center.x += (deltaW / 2) * lastAngleCos + (deltaH / 2) * lastAngleSin
            center.y += (deltaW / 2) * lastAngleSin - (deltaH / 2) * lastAngleCos
          } else {
            center.x += (deltaH / 2) * lastAngleSin
            center.y -= (deltaH / 2) * lastAngleCos
          }
        } else if (idx1 === 'r') {
          deltaH = -deltaH
          currentH = lastH + deltaH
          currentW = lastW + deltaW
          if (props.lockAspectRatio || (!props.lockAspectRatio && props.vertexRatio)) {
            if (currentH / currentW < tmpAspectRatio) {
              currentW = currentH / tmpAspectRatio
              deltaW = deltaH / tmpAspectRatio
            } else {
              currentH = currentW * tmpAspectRatio
              deltaH = deltaW * tmpAspectRatio
            }
          }
          center.x += (deltaW / 2) * lastAngleCos + (deltaH / 2) * lastAngleSin
          center.y += (deltaW / 2) * lastAngleSin - (deltaH / 2) * lastAngleCos
        }
        break
      case 'm':
        if (idx1 === 'l') {
          deltaW = -deltaW
          currentW = lastW + deltaW
          if (props.lockAspectRatio) {
            if (currentW / currentH > tmpAspectRatio) {
              currentH = currentW * tmpAspectRatio
              deltaH = deltaW * tmpAspectRatio
            } else {
              currentW = currentH / tmpAspectRatio
              deltaW = deltaH / tmpAspectRatio
            }
            // 右上角固定
            center.x -= (deltaW / 2) * lastAngleCos + (deltaH / 2) * lastAngleSin
            center.y -= (deltaW / 2) * lastAngleSin - (deltaH / 2) * lastAngleCos
          } else {
            // 右边固定
            center.x -= (deltaW / 2) * lastAngleCos
            center.y -= (deltaW / 2) * lastAngleSin
          }
        } else if (idx1 === 'r') {
          currentW = lastW + deltaW
          if (props.lockAspectRatio) {
            if (currentW / currentH > tmpAspectRatio) {
              currentH = currentW * tmpAspectRatio
              deltaH = deltaW * tmpAspectRatio
            } else {
              currentW = currentH / tmpAspectRatio
              deltaW = deltaH / tmpAspectRatio
            }
            // 右上角固定
            center.x += (deltaW / 2) * lastAngleCos - (deltaH / 2) * lastAngleSin
            center.y += (deltaW / 2) * lastAngleSin + (deltaH / 2) * lastAngleCos
          } else {
            // 右边固定
            center.x += (deltaW / 2) * lastAngleCos
            center.y += (deltaW / 2) * lastAngleSin
          }
        }
        break
      case 'b':
        if (idx1 === 'l') {
          deltaW = -deltaW
          currentW = lastW + deltaW
          currentH = lastH + deltaH
          if (props.lockAspectRatio || (!props.lockAspectRatio && props.vertexRatio)) {
            if (currentH / currentW < tmpAspectRatio) {
              currentW = currentH / tmpAspectRatio
              deltaW = deltaH / tmpAspectRatio
            } else {
              currentH = currentW * tmpAspectRatio
              deltaH = deltaW * tmpAspectRatio
            }
          }
          center.x -= (deltaW / 2) * lastAngleCos + (deltaH / 2) * lastAngleSin
          center.y -= (deltaW / 2) * lastAngleSin - (deltaH / 2) * lastAngleCos
        } else if (idx1 === 'm') {
          currentH = lastH + deltaH
          if (props.lockAspectRatio) {
            if (currentH / currentW < tmpAspectRatio) {
              currentW = currentH / tmpAspectRatio
              deltaW = deltaH / tmpAspectRatio
            } else {
              currentH = currentW * tmpAspectRatio
              deltaH = deltaW * tmpAspectRatio
            }
            // 左下角固定
            center.x += (deltaW / 2) * lastAngleCos - (deltaH / 2) * lastAngleSin
            center.y += (deltaW / 2) * lastAngleSin + (deltaH / 2) * lastAngleCos
          } else {
            center.x -= (deltaH / 2) * lastAngleSin
            center.y += (deltaH / 2) * lastAngleCos
          }
        } else if (idx1 === 'r') {
          currentW = lastW + deltaW
          currentH = lastH + deltaH
          if (props.lockAspectRatio || (!props.lockAspectRatio && props.vertexRatio)) {
            if (currentH / currentW < tmpAspectRatio) {
              currentW = currentH / tmpAspectRatio
              deltaW = deltaH / tmpAspectRatio
            } else {
              currentH = currentW * tmpAspectRatio
              deltaH = deltaW * tmpAspectRatio
            }
          }
          center.x += (deltaW / 2) * lastAngleCos - (deltaH / 2) * lastAngleSin
          center.y += (deltaW / 2) * lastAngleSin + (deltaH / 2) * lastAngleCos
        }
        break
    }

    setHeight(currentH)
    setWidth(currentW)
    // center位置相对左上角的，这里的left相对父元素
    const deltaLeft = center.x - currentW / 2 - (lastCenter.x - lastW / 2)
    const deltaTop = center.y - currentH / 2 - (lastCenter.y - lastH / 2)
    setLeft(lastX + deltaLeft)
    setTop(lastY + deltaTop)

    emit('resizing', {
      x: left.value,
      y: top.value,
      w: width.value,
      h: height.value,
      angle: angle.value,
    })
  }

  const resizeHandleUp = () => {
    emit('resize-end', {
      x: left.value,
      y: top.value,
      w: width.value,
      h: height.value,
    })
    // 恢复初始值
    setResizingHandle('')
    setResizing(false)
    setResizingMaxWidth(Infinity)
    setResizingMaxHeight(Infinity)
    setResizingMinWidth(props.minW)
    setResizingMinHeight(props.minH)

    // document.documentElement.removeEventListener('mousemove', resizeHandleDrag)
    // document.documentElement.removeEventListener('mouseup', resizeHandleUp)
    removeEvent(documentElement, MOVE_HANDLES, resizeHandleDrag)
    removeEvent(documentElement, UP_HANDLES, resizeHandleUp)
  }

  const resizeHandleDown = (e: HandleEvent, handleType: ResizingHandle) => {
    if (!props.resizable) return
    e.stopPropagation()
    setResizingHandle(handleType)
    setResizing(true)
    idx0 = handleType[0] // t m b
    idx1 = handleType[1] // l m r

    if (parent) {
      let maxHeight = idx0 === 't' ? top.value + height.value : parentHeight.value - top.value
      let maxWidth = idx1 === 'l' ? left.value + width.value : parentWidth.value - left.value
      // 锁定比例时
      if (props.lockAspectRatio) {
        if (maxHeight / maxWidth < aspectRatio.value) {
          maxWidth = maxHeight / aspectRatio.value
        } else {
          maxHeight = maxWidth * aspectRatio.value
        }
      }
      setResizingMaxHeight(maxHeight)
      setResizingMaxWidth(maxWidth)
    }

    // 初始位置，宽高
    lastW = width.value
    lastH = height.value
    lastX = left.value
    lastY = top.value
    lastAngle = angle.value
    const position = getPosition(e)
    lastPageX = position[0]
    lastPageY = position[1]
    tmpAspectRatio = aspectRatio.value
    // 获取元素相对于左上角的位置
    const rect = containerRef.value ? getElSize(containerRef.value) : { top: 0, left: 0 }
    // 获取旋转中心位置
    lastCenter = {
      x: rect.left + lastW / 2,
      y: rect.top + lastH / 2,
    }

    emit('resize-start', {
      x: left.value,
      y: top.value,
      w: width.value,
      h: height.value,
    })
    // document.documentElement.addEventListener('mousemove', resizeHandleDrag)
    // document.documentElement.addEventListener('mouseup', resizeHandleUp)
    addEvent(documentElement, MOVE_HANDLES, resizeHandleDrag)
    addEvent(documentElement, UP_HANDLES, resizeHandleUp)
  }

  onUnmounted(() => {
    // document.documentElement.removeEventListener('mouseup', resizeHandleDrag)
    // document.documentElement.removeEventListener('mousemove', resizeHandleUp)
    removeEvent(documentElement, UP_HANDLES, resizeHandleUp)
    removeEvent(documentElement, MOVE_HANDLES, resizeHandleDrag)
  })

  const handlesFiltered = computed(() => (props.resizable ? filterHandles(props.handles) : []))
  return {
    handlesFiltered,
    resizeHandleDown,
  }
}

// props外部改变值时
export function watchProps(props: any, limits: ReturnType<typeof initLimitSizeAndMethods>) {
  const { setWidth, setHeight, setLeft, setTop, setAngle } = limits
  watch(
    () => props.w,
    (newVal: number) => {
      setWidth(newVal)
    }
  )
  watch(
    () => props.h,
    (newVal: number) => {
      setHeight(newVal)
    }
  )
  watch(
    () => props.x,
    (newVal: number) => {
      setLeft(newVal)
    }
  )
  watch(
    () => props.y,
    (newVal: number) => {
      setTop(newVal)
    }
  )
  watch(
    () => props.angle,
    (newVal: number) => {
      setAngle(newVal)
    }
  )
}

// 初始化rotate
export function initRotateHandle(
  containerRef: Ref<HTMLElement | undefined>,
  containerProps: ReturnType<typeof initState>,
  props: any,
  emit: any
) {
  const { width, height, left, top, angle } = containerProps
  const { setRotating, setAngle } = containerProps
  const documentElement = document.documentElement
  let lastW = 0
  let lastH = 0
  let lastAngle = 0 // 角度
  let lastPageX = 0
  let lastPageY = 0
  // let tmpAspectRatio = 0
  // 旋转中心
  const center = {
    x: 0,
    y: 0,
  }
  // 开始旋转的向量
  const startVector = {
    x: 0,
    y: 0,
  }

  const rotateHandleRotate = (e: HandleEvent) => {
    if (e.stopPropagation) e.stopPropagation()
    if (e.preventDefault) e.preventDefault()
    // 阻止同类型事件触发
    e.stopImmediatePropagation()
    const [pageX, pageY] = getPosition(e)
    const rotateVector = {
      x: pageX - center.x,
      y: pageY - center.y,
    }
    const _angle = getAngle(startVector, rotateVector)
    const rotateAngle = Math.round(lastAngle + _angle)
    setAngle(rotateAngle)
    emit('rotating', {
      x: left.value,
      y: top.value,
      w: width.value,
      h: height.value,
      angle: _angle,
    })
  }
  const rotateHandleUp = () => {
    emit('rotate-end', {
      x: left.value,
      y: top.value,
      w: width.value,
      h: height.value,
      angle: angle.value,
    })
    // 恢复初始值
    setRotating(false)
    // document.documentElement.removeEventListener('mousemove', rotateHandleRotate)
    // document.documentElement.removeEventListener('mouseup', rotateHandleUp)
    removeEvent(documentElement, MOVE_HANDLES, rotateHandleRotate)
    removeEvent(documentElement, UP_HANDLES, rotateHandleUp)
  }

  const rotateDown = (e: HandleEvent) => {
    if (e.stopPropagation) e.stopPropagation()
    if (e.preventDefault) e.preventDefault()
    setRotating(true)
    // 初始位置，宽高
    lastW = width.value
    lastH = height.value
    lastAngle = angle.value
    const position = getPosition(e)
    lastPageX = position[0]
    lastPageY = position[1]
    // tmpAspectRatio = aspectRatio.value
    // 获取元素相对于左上角的位置
    const rect = containerRef.value ? getElSize(containerRef.value) : { top: 0, left: 0 }
    // 获取旋转中心位置
    center.x = rect.left + lastW / 2
    center.y = rect.top + lastH / 2
    // 计算出当前鼠标相对于元素中心点的坐标
    startVector.x = lastPageX - center.x
    startVector.y = lastPageY - center.y

    emit('rotate-start', {
      x: left.value,
      y: top.value,
      w: width.value,
      h: height.value,
      angle: angle.value,
    })

    // document.documentElement.addEventListener('mousemove', rotateHandleRotate)
    // document.documentElement.addEventListener('mouseup', rotateHandleUp)
    addEvent(documentElement, MOVE_HANDLES, rotateHandleRotate)
    addEvent(documentElement, UP_HANDLES, rotateHandleUp)
  }

  onUnmounted(() => {
    // document.documentElement.removeEventListener('mouseup', rotateHandleRotate)
    // document.documentElement.removeEventListener('mousemove', rotateHandleUp)
    removeEvent(documentElement, UP_HANDLES, rotateHandleUp)
    removeEvent(documentElement, MOVE_HANDLES, rotateHandleRotate)
  })

  return {
    rotateDown,
  }
}
